Skip to content

一、概述

Skywalking是一个可观测性分析平台(Observability Analysis Platform简称OAP)和应用性能管理系统(Application Performance Management简称APM)。

提供分布式链路追踪、服务网格(Service Mesh)遥测分析、度量(Metric)聚合和可视化一体化解决方案。

特点: 多语言自动探针,Java,.NET Core和Node.JS。 多种监控手段,语言探针和service mesh。 轻量高效。不需要额外搭建大数据平台。 模块化架构。UI、存储、集群管理多种机制可选。 支持告警。 优秀的可视化效果。

1.1 整体架构

skywalking架构

Skywalking提供Tracing和Metrics数据的获取和聚合。

Metric的特点是,它是可累加的:他们具有原子性,每个都是一个逻辑计量单元,或者一个时间段内的柱状图。 例如:队列的当前深度可以被定义为一个计量单元,在写入或读取时被更新统计; 输入HTTP请求的数量可以被定义为一个计数器,用于简单累加; 请求的执行时间可以被定义为一个柱状图,在指定时间片上更新和统计汇总。 Tracing的最大特点就是,它在单次请求的范围内,处理信息。 任何的数据、元数据信息都被绑定到系统中的单个事务上。 例如:一次调用远程服务的RPC执行过程;一次实际的SQL查询语句;一次HTTP请求的业务性ID。

总结,Metric主要用来进行数据的统计,比如HTTP请求数的计算。Tracing主要包含了某一次请求的链路数据。 详细的内容可以查看Skywalking开发者吴晟翻译的文章,Metrics, tracing 和 logging 的关系 :http://blog.oneapm.com/apm-tech/811.html

整体架构包含如下三个组成部分:

  1. 探针(agent)负责进行数据的收集,包含了Tracing和Metrics的数据,agent会被安装到服务所在的服务器上,以方便数据的获取。
  2. 可观测性分析平台OAP(Observability Analysis Platform),接收探针发送的数据,并在内存中使用分析引擎(Analysis Core)进行数据的整合运算,然后将数据存储到对应的存储介质上,比如Elasticsearch、MySQL数据库、H2数据库等。同时OAP还使用查询引擎(Query Core)提供HTTP查询接口。
  3. Skywalking提供单独的UI进行数据的查看,此时UI会调用OAP提供的接口,获取对应的数据然后进行展示。

1.2 优势

Skywalking相比较其他的分布式链路监控工具,具有以下特点:

社区相当活跃。Skywalking已经进入apache孵化,目前的start数已经超过11K,最新版本6.5.0已经发布。开发者是国人,可以直接和项目发起人交流进行问题的解决。 Skywalking支持Java,.NET Core和Node.JS语言。相对于其他平台:比如Pinpoint支持Java和PHP,具有较大的优势。 探针无倾入性。对比CAT具有倾入性的探针,优势较大。不修改原有项目一行代码就可以进行集成。 探针性能优秀。有网友对Pinpoint和Skywalking进行过测试,由于Pinpoint收集的数据过多,所以对性能损耗较大,而Skywalking探针性能十分出色。 支持组件较多。特别是对Rpc框架的支持,这是其他框架所不具备的。Skywalking对Dubbo、gRpc等有原生的支持,甚至连小众的motan和sofarpc都支持。

1.3 主要概念

Skywalking主要概念包含:服务(Service)、端点(Endpoint)、实例(Instance)

用户服务就是Skywalking的服务(Service),用户服务其实就是一个独立的应用(Application),在6.0之后的Skywalking将应用更名为服务(Service)。 用户服务对外提供的HTTP接口/usr/queryAll就是一个端点,端点就是对外提供的接口。

192.168.1.100和192.168.1.101这两个相同服务部署的节点就是实例,实例指同一服务可以部署多个。

二、使用示例

2.1 tomcat引用

sh
#linux  注意可能与ui端口冲突
# 编辑 /usr/local/skywalking/apache-tomcat-8.5.47/bin/catalina.sh 文件,在文件顶部添加:


<NolebasePageProperties />




CATALINA_OPTS="$CATALINA_OPTS -javaagent:/usr/local/skywalking/apache- skywalking-apm-bin/agent/skywalking-agent.jar"; export CATALINA_OPTS

# windows
#修改f tomcat目录/bin/catalina.bat 文件的第一行
set "CATALINA_OPTS=-javaagent:/path/to/skywalking-agent/skywalking-agent.jar"

2.2 Spring Boot中使用

Skywalking与Spring Boot集成提供了完善的支持。 使用命令启动springboot项目

sh
# 使用jar包启动的项目如果需要集成skywalking,需要添加-javaagent参数,参数值为agent的jar包所在位置。
java -javaagent:/usr/local/skywalking/apache-skywalking-apm- bin/agent_boot/skywalking-agent.jar -Dserver.port=8082 -jar skywalking_springboot.jar &

三、核心知识

3.1 agent使用

agent探针可以让我们不修改代码的情况下,对java应用上使用到的组件进行动态监控,获取运行数据发送到OAP上进行统计和存储。agent探针在java中是使用java agent技术实现的,不需要更改任何代码,java agent会通过虚拟机(VM)接口来在运行期更改代码。

agent原理

Java agent是java命令的一个参数。参数 javaagent 可以用于指定一个 jar 包。

  1. 这个 jar 包的 MANIFEST.MF 文件必须指定 Premain-Class 项。
  2. Premain-Class 指定的那个类必须实现 premain() 方法。

当Java 虚拟机启动时,在执行 main 函数之前,JVM 会先运行 -javaagent 所指定 jar 包内 PremainClass 这个类的 premain 方法 。

agen使用示例

使用 java agent 需要几个步骤:

  1. 定义一个 MANIFEST.MF 文件,必须包含 Premain-Class 选项,通常也会加入Can-RedefineClasses 和 Can-Retransform-Classes 选项。
  2. 创建一个Premain-Class 指定的类,类中包含 premain 方法,方法逻辑由用户自己确定。
  3. 将 premain 的类和 MANIFEST.MF 文件打成 jar 包。
  4. 使用参数 -javaagent: jar包路径 启动要代理的方法。

类中提供两个静态方法,方法名均为premain,不能拼错。

java
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

public class PreMainAgent {

    //    /**
//     * 在这个 premain 函数中,开发者可以进行对类的各种操作。
//     * 1、agentArgs 是 premain 函数得到的程序参数,随同 “– javaagent”一起传入。与 main 函数不同的是,
//     * 这个参数是一个字符串而不是一个字符串数组,如果程序参数有多个,程序将自行解析这个字符串。
//     * 2、Inst 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入。*
//     * java.lang.instrument.Instrumentation 是 instrument 包中定义的一个接口,也是这个包的核心部分,
//     * 集中了其中几乎所有的功能方法,例如类定义的转换和操作等等。
//     * @param agentArgs
//     * @param inst
//     */
//    public static void premain(String agentArgs, Instrumentation inst) {
//        System.out.println("=========premain方法执行1========");
//        System.out.println(agentArgs);
//    }
//
//    /**
//     * 如果不存在 premain(String agentArgs, Instrumentation inst)
//     * 则会执行 premain(String agentArgs)
//     * @param agentArgs
//     */
//    public static void premain(String agentArgs) {
//        System.out.println("=========premain方法执行2========");
//        System.out.println(agentArgs);
//    }
    public static void premain(String agentArgs, Instrumentation inst) {
        //创建一个转换器,转换器可以修改类的实现
        //ByteBuddy对java agent提供了转换器的实现,直接使用即可
        AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
            public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) {
                return builder
                        // 拦截任意方法
                        .method(ElementMatchers.<MethodDescription>any())
                        // 拦截到的方法委托给TimeInterceptor
                        .intercept(MethodDelegation.to(MyInterceptor.class));
            }
        };
        new AgentBuilder // Byte Buddy专门有个AgentBuilder来处理Java Agent的场景
                .Default()
                // 根据包名前缀拦截类
                .type(ElementMatchers.nameStartsWith("com.agent"))
                // 拦截到的类由transformer处理
                .transform(transformer)
                .installOn(inst);
    }
}

在pom文件中添加打包插件:

xml

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <appendAssemblyId>false</appendAssemblyId>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <!--自动添加META-INF/MANIFEST.MF -->
                        <manifest>
                            <addClasspath>true</addClasspath>
                        </manifest>
                        <manifestEntries>
                            <Premain-Class>PreMainAgent</Premain-Class>
                            <Agent-Class>PreMainAgent</Agent-Class>
                            <Can-Redefine-Classes>true</Can-Redefine-Classes>
                            <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        </manifestEntries>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

该插件会在自动生成META-INF/MANIFEST.MF文件时,帮我们添加agent相关的配置信息。

使用maven的package命令进行打包 打包后通过-javaagent:路径\java-agent-demo-1.0-SNAPSHOT.jar=HELLOAGENT即可运行Java agent的代码逻辑 java agent的代码优先于MAIN函数的方法运行

在Skywalking中相关引用

Agent探针支持 JDK 1.6 - 12的版本,Agent探针所有的文件在Skywalking的agent文件夹下

+-- agent
	+-- activations 
		apm-toolkit-log4j-1.x-activation.jar 
		apm-toolkit-log4j-2.x-activation.jar
        apm-toolkit-logback-1.x-activation.jar 
        ... 
	//配置文件 
	+-- config
    	agent.config 
	//组件的所有插件 
	+-- plugins 
		apm-dubbo-plugin.jar 
		apm-feign-default-http-9.x.jar 
		apm-httpClient-4.x-plugin.jar 
		..... 
	//可选插件
    +-- optional-plugins 
    	apm-gson-2.x-plugin.jar 
    	..... 
	+-- bootstrap-plugins 
		jdk-http-plugin.jar 
		..... 
	+-- logs 
		skywalking-agent.jar

部分插件在使用上会影响整体的性能或者由于版权问题放置于可选插件包中,不会直接加载,如果需要使用,将可选插件中的jar包拷贝到plugins包下。

由于没有修改agent探针中的应用名,所以默认显示的是Your_ApplicationName。

properties
# cd /usr/local/skywalking/apache-skywalking-apm-bin/agent/config 
# vi agent.config  
# The service name in UI   
# 读取到SW_AGENT_NAME配置属性,如果该配置没有指定,那么默认名称为Your_ApplicationName。  
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}

3.2 RocketBot的使用

Skywalking的监控UI页面成为RocketBot,我们可以通过 8080 端口进行访问,相关配置可通过修改webapp/webapp.yml修改。

仪表盘

打开RocketBot默认会出现仪表盘页面:

仪表盘页面分为两大块:

  • 服务仪表盘,展示服务的调用情况
  • 数据库仪表盘,展示数据库的响应时间等数据

选中服务仪表盘,有四个维度的统计数据可以进行查看:

  • 全局,查看全局接口的调用,包括全局响应时长的百分比,最慢的端点,服务的吞吐量等
  • 服务,显示服务的响应时长、SLA、吞吐量等信息
  • 端点,显示端点的响应时长、SLA、吞吐量等信息
  • 实例,显示实例的响应时长、SLA、吞吐量等信息,还可以查看实例的JVM的GC信息、CPU信息、内存信息

拓扑图

Skywalking提供拓扑图,直观的查看服务之间的调用关系 User代表用户应用,目前案例中其实是浏览器 Skywalking_boot应用被User调用,同时显示它是一个Spring MVC的应用。后续案例中会出现多个应用调用,使用拓扑图就能清楚的分析其调用关系了。

追踪

在Skywalking中,每一次用户发起一条请求,就可以视为一条追踪数据,每条追踪数据携带有一个ID值。追踪数据在追踪页面中可以进行查询: 左侧是追踪列表,也可以通过上方的追踪ID来进行查询。点击追踪列表某一条记录之后,右侧会显示出此条追踪的详细信息。有三种显示效果: 列表、树结构、表格

可以很好的展现此条追踪的调用链情况而链路上每个节点,可以通过左键点击节点查看详细信息: 当前的接口是HTTP的GET请求,相对比较简单,后续的示例中出现异常情况或者数据库访问,可以打印出异常信息、堆栈甚至详细的SQL语句。

告警

Skywalking中的告警功能相对比较简单,在达到告警阈值之后会生成一条告警记录,在告警页面上进行展示。

3.3 Rpc调用监控

Skywalking(6.5.0) 支持的Rpc框架有以下几种: Dubbo 2.5.4 -> 2.6.0、Dubbox 2.8.4、Apache Dubbo 2.7.0、Motan 0.2.x -> 1.1.0、gRPC 1.x、Apache ServiceComb Java Chassis 0.1 -> 0.5,1.0.x、SOFARPC 5.4.0 同springboot应用集成方式。

3.4 MySql调用监控

项目中集成mysql查询sql即可进行监控 同springboot应用集成方式。

3.5常用插件

配置覆盖

系统配置 使用 skywalking. + 配置文件中的配置名作为系统配置项来进行覆盖

sh
# 进行 agent.service_name 的覆盖  
-Dskywalking.agent.service_name=skywalking_mysql

探针配置(Agent options)

sh
# -javaagent:/path/to/skywalking-agent.jar=[option1]=[value1],[option2]=[value2]  
  
# 进行 agent.service_name 的覆盖  
-javaagent:/path/to/skywalking-agent.jar=agent.service_name=skywalking_mysql  
  
# 如果配置中包含分隔符( , 或者 = ) , 就必须使用引号包裹起来  
-javaagent:/path/to/skywalking-agent.jar=agent.ignore_suffix='.jpg,.jpeg'

系统环境变量(System environment variables)

sh
# The service name in UI   
# 可以在环境变量中设置SW_AGENT_NAME的值来指定服务名。  
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}

覆盖优先级 探针配置 > 系统配置 >系统环境变量 > 配置文件中的值

获取追踪ID

Skywalking提供我们Trace工具包,用于在追踪链路时进行信息的打印或者获取对应的追踪ID 使用TraceContext.traceId()可以打印出当前追踪的ID,方便在RocketBot中进行搜索。

ActiveSpan提供了三个方法进行信息的打印: error方法会将本次调用变为失败状态,同时可以打印对应的堆栈信息和错误提示。 info方法打印info级别的信息。 debug方法打印debug级别的信息。

过滤指定的端点

在开发过程中,有一些端点(接口)并不需要去进行监控,比如Swagger相关的端点。这个时候我们就可以使用Skywalking提供的过滤插件来进行过滤 在jar包启动时通过参数指定哪些需要过滤

sh
# 加-Dskywalking.trace.ignore_path=/exclude参数来标识需要过滤哪些请求,支持 Ant Path 表达式:  
# ? 匹配任何单字符  
# * 匹配0或者任意数量的字符  
# ** 匹配0或者更多的目录  
java -javaagent:/usr/local/skywalking/apache-skywalking-apm- bin/agent/skywalking-agent.jar - Dskywalking.agent.service_name=skywalking_plugins - Dskywalking.trace.ignore_path=/exclude jar skywalking_plugins.jar &

3.6 告警功能

Skywalking每隔一段时间根据收集到的链路追踪的数据和配置的告警规则(如服务响应时间、服务响应时间百分比)等,判断如果达到阈值则发送相应的告警信息。发送告警信息是通过调用webhook接口完成,具体的webhook接口可以使用者自行定义,从而开发者可以在指定的webhook接口中编写各种告警方式,比如邮件、短信等。告警的信息也可以在RocketBot中查看到。 默认的告警规则配置位于skywalking安装目录下的confifig文件夹下 alarm-settings.yml 文件中,其中定义了默认的4中规则

  1. 最近3分钟内服务的平均响应时间超过1秒
  2. 最近2分钟服务成功率低于80%
  3. 最近3分钟90%服务响应时间超过1秒
  4. 最近2分钟内服务实例的平均响应时间超过1秒

规则中的参数属性如下:

属性含义
metrics-nameoal脚本中的度量名称
threshold阈值,与metrics-name和下面的比较符号相匹配
op比较操作符,可以设定>,<,=
period多久检查一次当前的指标数据是否符合告警规则,单位分钟
count达到多少次后,发送告警消息
silence-period在多久之内,忽略相同的告警消息
message告警消息内容
include-names本规则告警生效的服务列表

webhooks可以配置告警产生时的调用地址。

3.7 统计方法调用时间

Skywalking中对每个调用的时长都进行了统计,使用ByteBuddy和Java agent技术来统计方法的调用时长。

Byte Buddy是开源的、基于Apache 2.0许可证的库,它致力于解决字节码操作和instrumentation API的复杂性。Byte Buddy所声称的目标是将显式的字节码操作隐藏在一个类型安全的领域特定语言背后。通过使用Byte Buddy,任何熟悉Java编程语言的人都有望非常容易地进行字节码操作。ByteBuddy提供了额外的API来生成Java agent,可以轻松的增强我们已有的代码。

依赖

xml
<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <version>1.9.2</version>
</dependency>
<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy-agent</artifactId>
    <version>1.9.2</version>
</dependency>

修改PreMainAgent代码

先生成一个转换器,ByteBuddy提供了java agent专用的转换器。通过实现Transformer接口利用builder对象来创建一个转换器。转换器可以配置拦截方法的格式,比如用名称,本例中拦截所有方法,并定义一个拦截器类MyInterceptor。 创建完拦截器之后可以通过Byte Buddy的AgentBuilder建造者来构建一个agent对象。AgentBuilder可以对指定的包名前缀来生效,同时需要指定转换器对象。

java
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class MyInterceptor {
    @RuntimeType
    public static Object intercept(@Origin Method method,
                                   @SuperCall Callable<?> callable)
            throws Exception {
        long start = System.currentTimeMillis();
        try {
            //执行原方法
            return callable.call();
        } finally {
            //打印调用时长
            System.out.println(method.getName() + ":" + (System.currentTimeMillis() - start)  + "ms");
        }
    }
}

MyInterceptor就是一个拦截器的实现,统计的调用的时长。参数中的method是反射出的方法对象,而callable就是调用对象,可以通过callable.call()方法来执行原方法

重新打包通过命令加载java agent

四、安装

4.1 常规安装

安装步骤可以在Skywalking的官方github上找到:https://github.com/apache/skywalking/blob/master/docs/en/setup/README.md

安装elasticsearch

需要安装elasticsearch并修改改Linux系统的限制配置,将文件创建数修改为65536个。

  1. 修改系统中允许应用最多创建多少文件等的限制权限。Linux默认来说,一般限制应用最多创建的文件是65535个。但是ES至少需要65536的文件创建数的权限。
  2. 修改系统中允许用户启动的进程开启多少个线程。默认的Linux限制root用户开启的进程可以开启任意数量的线程,其他用户开启的进程可以开启1024个线程。必须修改限制数为4096+。因为ES至少需要4096的线程池预备。
sh
vi /etc/security/limits.conf 
#新增如下内容在limits.conf文件中
es soft nofile 65536
es hard nofile 65536
es soft nproc 4096
es hard nproc 4096

修改系统控制权限,ElasticSearch需要开辟一个65536字节以上空间的虚拟内存。Linux默认不允许任何用户和应用程序直接开辟这么大的虚拟内存。

sh
vi /etc/sysctl.conf
#新增如下内容在sysctl.conf文件中,当前用户拥有的内存权限大小 
vm.max_map_count=262144
#让系统控制权限配置生效 
sysctl -p

建一个用户, 用于ElasticSearch启动。 ES在5.x版本之后,强制要求在linux中不能使用root用户启动ES进程。所以必须使用其他用户启动ES进程才可以。

sh
#创建用户
useradd es 
#修改上述用户的密码 
passwd es
#修改elasicsearch目录的拥有者 
chown -R es elasticsearch-6.4.0
#切换用户 
su es
#到ElasticSearch的bin目录下 
cd bin/ 
#后台启动
./elasticsearch -d

默认ElasticSearch是不支持跨域访问的,所以在不修改配置文件的情况下我们只能从虚拟机内部进行访问测试ElasticSearch是否安装成功,使用curl命令访问9200端口,有返回响应信息,则安装成功。

sh
curl http://localhost:9200

安装Skywalking

切回到root用户,切换到目录下,解压Skywalking压缩包。

sh
#切换到root用户 
su root
#切换到skywalking目录
cd /usr/local/skywalking 
#解压压缩包 
tar -zxvf apache-skywalking-apm-6.4.0.tar.gz

修改Skywalking存储的数据源配置:

yml
# config/application.yml
#将默认的h2全部注释
# h2: 
# driver: ${SW_STORAGE_H2_DRIVER:org.h2.jdbcx.JdbcDataSource} 
# url: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db}
# user: ${SW_STORAGE_H2_USER:sa} 
# metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000} 
# mysql: # metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}

# ElasticSearch对应的配置取消注释
storage:
  elasticsearch:
    nameSpace: ${SW_NAMESPACE:""} 
    clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
    protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"http"} 
    trustStorePath: ${SW_SW_STORAGE_ES_SSL_JKS_PATH:"../es_keystore.jks"}
    trustStorePass: ${SW_SW_STORAGE_ES_SSL_JKS_PASS:""} 
    user: ${SW_ES_USER:""}
    password: ${SW_ES_PASSWORD:""}
    indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:2}
    indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:0} 
    # Those data TTL settings will override the same settings in core module.
    recordDataTTL: ${SW_STORAGE_ES_RECORD_DATA_TTL:7} # Unit is day
    otherMetricsDataTTL: ${SW_STORAGE_ES_OTHER_METRIC_DATA_TTL:45} # Unit is day 
    monthMetricsDataTTL: ${SW_STORAGE_ES_MONTH_METRIC_DATA_TTL:18} # Unit is month
    # # Batch process setting, refer to https://www.elastic.co/guide/en/elasticsearch/client/java-api/5.5/java-docs- bulk-processor.html 
    bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:1000} # Execute the bulk every 1000 requests 
    flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:10} # flush the bulk every 10 seconds whatever the number of requests 
    concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2} # the number of concurrent requests
    metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:5000}
    segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}

启动OAP程序

sh
bin/oapService.sh

安装UI

yaml
# cat webapp/webapp.yml
#默认启动端口
server: 
  port: 8080 
  
collector: 
  path: /graphql
  ribbon:
    ReadTimeout: 10000
    #OAP服务,如果有多个用逗号隔开 
    listOfServers: 127.0.0.1:12800
sh
/bin/webappService.sh

# /bin/startup.sh可以同时启动backend和ui,后续可以执行该文件进行重启。